#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seamcarving.h"
#include "dinamico.h"
#include "grafo.h"
#include "io.h"
#include "ppm.h"

void AlocarValorCor(Imagem *imagem, int intensidade, int cor, int linha, int coluna)
{
	switch(cor) {
	case 0:
		imagem->imagem[linha][coluna].pixelRED = intensidade;
		break;
	case 1:
		imagem->imagem[linha][coluna].pixelGREEN = intensidade;
		break;
	case 2:
		imagem->imagem[linha][coluna].pixelBLUE = intensidade;
		break;
	default:
		printf("Erro no preenchimento da matriz!\n");
		exit(1);
	}
}

void LeEntrada(Imagem *imagem, char *entrada)
{
	FILE *arq = fopen(entrada, "r");

	int cor = 0;
	char valor[100];
	char comentario[100];
	char titulo[3];
	int valores[3];
	int i = 0;
	int linha = 0;
	int coluna = 0;
	int saltaLinha;

	if(arq == NULL)
	{
		printf("Erro na abertura do arquivo de entrada\n");
		exit(1);
	}

	fscanf(arq, "%s", titulo);
	while(!feof(arq))
	{
		saltaLinha = 1;
		fscanf(arq, "%s", valor);

		//Descarta linha comentada
		if(!strcmp(valor, "#"))
		{
			fgets(comentario, 100, arq);
			saltaLinha = 0;
		}
		//Condição para preenchimento dos valores: Linha, Coluna da matriz e a intensidade do pixl
		if((i < 3) && (strcmp(valor, "#")))
		{
			valores[i] = atoi(valor); //Posição 0 = linhas/ Posição 1 = colunas / Posição 2 = intensidade
			i++;
			if((i == 3) && (imagem->imagem == NULL))
			{
				imagem->imagem = AlocaMatrizImagem(valores[1], valores[0]);
				imagem->numColunas = valores[0];
				imagem->numLinhas = valores[1];
				imagem->intensidadeRGB = valores[2];
			}
		}

		//Condição para preenchimento da matriz de pixels
		else if(imagem->imagem != NULL)
		{
			if(linha < imagem->numLinhas && coluna < imagem->numColunas && saltaLinha)
			{
				AlocarValorCor(imagem, atoi(valor), cor, linha, coluna);
				cor++;
				if(cor == 3)
				{
					coluna++;
					cor = 0;
				}

				if(coluna == imagem->numColunas)
				{
					linha++;
					coluna = 0;
				}
			}
		}
	}
	fclose(arq);
}

void ApagaImagem(Imagem *imagem)
{
	ApagaMatrizPixel(imagem->imagem, imagem->numLinhas, imagem->numColunas);
	imagem->imagem = NULL;
	imagem->intensidadeRGB = 0;
	imagem->numColunas = 0;
	imagem->numLinhas = 0;
}
void ApagaMatrizPixel(Pixel **pixels, int numLinhas, int numColunas)
{
	int  i;  /* variavel auxiliar */
	if (pixels == NULL) return;


	for (i=0; i<numLinhas; i++)
	{
		free(pixels[i]);
	}
	free(pixels);
}
void CopiaImagem(Imagem *original, Imagem *nova)
{
	int i, j;
	for(i=0; i<original->numLinhas; i++)
	{
		for(j=0; j<original->numColunas; j++)
		{
			nova->imagem[i][j].energia = original->imagem[i][j].energia;
			nova->imagem[i][j].pixelRED = original->imagem[i][j].pixelRED;
			nova->imagem[i][j].pixelGREEN = original->imagem[i][j].pixelGREEN;
			nova->imagem[i][j].pixelBLUE = original->imagem[i][j].pixelBLUE;
		}
	}
	nova->intensidadeRGB = original->intensidadeRGB;
	nova->numColunas = original->numColunas;
	nova->numLinhas = original->numLinhas;
}


void SeamCarving(Imagem *original, char *estrategia, char *comando, int quantidadeParaRetirar)
{
	Imagem imagemReduzida, imagemFinal;
	int contador = 0; //Conta quantas linhas ja foram rertiradas
	InicializaImagem(&imagemReduzida);
	InicializaImagem(&imagemFinal);
	AtribuirValoresImagemReduzida(original, &imagemReduzida);
	int **intensidadeLuminosa = AlocaMatrizInt(original->numLinhas, original->numColunas);
	//Imprimir(&imagem);
	//printf("\n");
	CalcIntensidadeLuminosa(original, intensidadeLuminosa);
//	ImprimeMatrizInt(intensidadeLuminosa, original->numLinhas, original->numColunas);
//	printf("\n");
	FiltroSobel(original, intensidadeLuminosa, original->numLinhas, original->numColunas);
//	ImprimeMatrizEnergia(original, original->numLinhas, original->numColunas);
//	printf("\n");
	if(!strcmp(estrategia, "D"))
	{
		if(!strcmp(comando, "-w"))
		{
			if(quantidadeParaRetirar > 0)
			{
				SeamCarvingDinamico(original, &imagemReduzida, original->numLinhas, original->numColunas);
				contador++;

				while(contador < quantidadeParaRetirar)
				{
					ApagaImagem(&imagemFinal);
					imagemFinal.imagem = AlocaMatrizImagem(original->numLinhas, (original->numColunas - (contador + 1)));
					AtribuirValoresImagemReduzida(&imagemReduzida, &imagemFinal);
					SeamCarvingDinamico(&imagemReduzida, &imagemFinal, original->numLinhas, (original->numColunas - contador));
					ApagaImagem(&imagemReduzida);
					imagemReduzida.imagem = AlocaMatrizImagem(original->numLinhas, (original->numColunas - (contador + 1)));
					CopiaImagem(&imagemFinal, &imagemReduzida);
					contador++;
				}
			}
		}
		else if(!strcmp(comando, "-h"))
		{

		}

	}
	else if (!strcmp(estrategia, "G"))
	{

	}
	else
	{
		printf("Parametro errado para definir estrategia. Utilize G ou D no terceiro parametro da linha de comando");
	}

	//Imprimir(reduzida);
	ImprimirArquivo(&imagemFinal);
}














void Imprimir(Imagem *imagem)
{
	int i, j;
	printf("%d %d %d\n", imagem->numLinhas, imagem->numColunas, imagem->intensidadeRGB);

	for(i=0; i<imagem->numLinhas; i++)
	{
		for(j=0; j<imagem->numColunas; j++)
		{
			printf("%d\t %d\t %d\t",imagem->imagem[i][j].pixelRED, imagem->imagem[i][j].pixelGREEN, imagem->imagem[i][j].pixelBLUE);
		}
		printf("\n");
	}
	printf("\n");
}

void ImprimirArquivo(Imagem *imagem)
{
	int i, j;
	FILE *arq = fopen("saida.ppm", "w");
	fprintf(arq, "P3\n");
	fprintf(arq, "%d %d\n%d\n", imagem->numColunas, imagem->numLinhas, imagem->intensidadeRGB);

	for(i=0; i<imagem->numLinhas; i++)
	{
		for(j=0; j<imagem->numColunas; j++)
		{
			fprintf(arq, "%d %d %d ",imagem->imagem[i][j].pixelRED, imagem->imagem[i][j].pixelGREEN, imagem->imagem[i][j].pixelBLUE);
		}
		fprintf(arq, "\n");
	}
	fprintf(arq, "\n");
	fclose(arq);
}

void ImprimeMatrizInt(int **imagem, int tamanhoLinha, int tamanhoColuna)
{
	int i, j;
	for(i=0; i<tamanhoLinha; i++)
	{
		for(j=0; j<tamanhoColuna; j++)
		{
			printf("%d\t", imagem[i][j]);
		}
		printf("\n");
	}
}

void ImprimeMatrizEnergia(Imagem *imagem, int tamanhoLinha, int tamanhoColuna)
{
	int i, j;
	for(i=0; i<tamanhoLinha; i++)
	{
		for(j=0; j<tamanhoColuna; j++)
		{
			printf("%d\t", imagem->imagem[i][j].energia);
		}
		printf("\n");
	}
}

double **AlocaMatrizDouble(int L, int C)
{
	double **v;  /* ponteiro para a matriz */
	int   i;    /* variavel auxiliar      */

	  /* aloca as linhas da matriz */
	  v = (double **) malloc(L * sizeof(double *));
	  if (v == NULL) {
	     printf ("** Erro: Memoria Insuficiente **");
	     return (NULL);
	     }
	  /* aloca as colunas da matriz */
	  for ( i = 0; i < L; i++ ) {
	      v[i] = (double*)malloc(C*sizeof(double));
	      if (v[i] == NULL) {
	         printf ("** Erro: Memoria Insuficiente **");
	         return (NULL);
	         }
	      }
	  return (v); /* retorna o ponteiro para a matriz */
}

int **AlocaMatrizInt(int L, int C)
{
	int **v;  /* ponteiro para a matriz */
	int   i;    /* variavel auxiliar      */

	  /* aloca as linhas da matriz */
	  v = (int **) malloc(L * sizeof(int *));
	  if (v == NULL) {
	     printf ("** Erro: Memoria Insuficiente **");
	     return (NULL);
	     }
	  /* aloca as colunas da matriz */
	  for ( i = 0; i < L; i++ ) {
	      v[i] = (int*)malloc(C*sizeof(int));
	      if (v[i] == NULL) {
	         printf ("** Erro: Memoria Insuficiente **");
	         return (NULL);
	         }
	      }
	  return (v); /* retorna o ponteiro para a matriz */
}
